package Export;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

import javax.swing.JFileChooser;

import DataModel.Feature;
import DataModel.FeatureHolder;
import DataModel.LociHolder;
import Interfaces.Track;
import Viewer.Viewer;

/**
 * This class is for export an gbk file from selected {@link Feature}s.<br>
 * <a href="http://www.ncbi.nlm.nih.gov/Sitemap/samplerecord">http://www.ncbi.nlm.nih.gov/Sitemap/samplerecord</a>
 * 
 * @author Stefan Lorenz<br>
 * <br>26.11.2012
 */
public class ExportGenBank {

	/**
	 * The GeneScapes viewer to get information about the data
	 */
	private Viewer viewer;
	/**
	 * Features to export as a {@link Track}
	 */
	private Track exportFeatures;

	/**
	 * Constructor of the GenkBank exporter
	 * @param viewer the viewer of the browser
	 * @param exportFeatures the features to export as a track
	 */
	public ExportGenBank(Viewer viewer, Track exportFeatures) {
		this.viewer = viewer;
		this.exportFeatures = exportFeatures;
		try {
			exportGenBank();
		}
		catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Writes the genbank file. If the selected freatures are from an genbank header etc.
	 * are taken. Otherwise an empty header gets written to the file.
	 * @throws IOException
	 */
	private void exportGenBank() throws IOException{
		if (this.viewer.getFileChooser().showSaveDialog(this.viewer) == JFileChooser.APPROVE_OPTION) {
			File file = this.viewer.getFileChooser().getSelectedFile();
			if(!(file.getName().endsWith(".gbk") || file.getName().endsWith(".gb")))
				file = new File(file.getAbsolutePath()+".gbk");
			
			BufferedWriter writer = new BufferedWriter(new FileWriter(file));
			// check if selected features are from a gbk, than use the header of the reference file
			if (this.viewer.getLoadedTracks()[1].getTypeOfFile().equals("gbk")) {
				BufferedReader reader = new BufferedReader(new FileReader(this.viewer.getLoadedTracks()[1].getFile()));
				String actualString = "";

				while ((actualString = reader.readLine()) != null) {
					writer.write(actualString);
					writer.newLine();
					writer.flush();
					if (actualString.startsWith("FEATURES")) {
						break;
					}
				}
				reader.close();
			}
			// otherwise write empty header
			else {
				writer.write("LOCUS       "+exportFeatures.getName()+"            "+exportFeatures.getSize()+" bp    DNA     linear   PLN date");
				writer.newLine();
				writer.write("DEFINITION  ..");
				writer.newLine();
				writer.write("ACCESSION   ..");
				writer.newLine();
				writer.write("VERSION     ..");
				writer.newLine();
				writer.write("DBLINK      ..");
				writer.newLine();
				writer.write("KEYWORDS    ..");
				writer.newLine();
				writer.write("SOURCE      ..");
				writer.newLine();
				writer.write("  ORGANISM  ..");
				writer.newLine();
				writer.write("REFERENCE 1");
				writer.newLine();
				writer.write("  AUTHORS ..");
				writer.newLine();
				writer.write("  TITLE ..");
				writer.newLine();
				writer.write("  JOURNAL ..");
				writer.newLine();
				writer.write("COMMENT ..");
				writer.newLine();
				writer.write("FEATURES            Location/Qualifiers");
				writer.newLine();
				writer.flush();
			}
			// Bucket List cause file type
			if (exportFeatures.getTypeOfFile().equals("gbk") ||
					exportFeatures.getTypeOfFile().equals("fasta") ||
					exportFeatures.getTypeOfFile().equals("embl")) {

				LociHolder genome = (LociHolder) exportFeatures;
				for (int i = 0; i < genome.getListOfLoci().get(0).getBucketList().size(); i++) {

					for (int j = 0; j < genome.getListOfLoci().get(0).getBucketList().get(i).getFeaturesOfBucket().size(); j++) {
						try {
							writeGenBankFeature(writer, genome.getListOfLoci().get(0).getBucketList().get(i).getFeaturesOfBucket().get(j));
							writer.newLine();
						}
						catch (Exception e) {
							System.out.println("Can not export feature");
						}
					}
				}
			}
			// Read file format wig gff gtf bed etc normal feature list
			else if (exportFeatures.getTypeOfFile().equals("gff") ||
					exportFeatures.getTypeOfFile().equals("gtf") ||
					exportFeatures.getTypeOfFile().equals("sam") ||
					exportFeatures.getTypeOfFile().equals("bed")) {
			    FeatureHolder genome = (FeatureHolder) exportFeatures;
				for (int i = 0; i < genome.size(); i++) {

					try {
						writeGenBankFeature(writer, genome.get(i));
						writer.newLine();
					}
					catch (Exception e) {
						System.out.println("Can not export feature");
					}
				}
			}
			
			// Write sequence section
			writer.write("ORIGIN");
			//No sequence in reference can't write 
			if (this.viewer.getLoadedTracks()[1].getTypeOfFile().equals("gff") ||
					this.viewer.getLoadedTracks()[1].getTypeOfFile().equals("gtf") ||
					this.viewer.getLoadedTracks()[1].getTypeOfFile().equals("sam") ||
					this.viewer.getLoadedTracks()[1].getTypeOfFile().equals("bed")) {
				writer.newLine();
				writer.write("//");
			}
			else if (this.viewer.getLoadedTracks()[1].getTypeOfFile().equals("gbk") ||
					this.viewer.getLoadedTracks()[1].getTypeOfFile().equals("fasta") ||
					this.viewer.getLoadedTracks()[1].getTypeOfFile().equals("fas") ||
					this.viewer.getLoadedTracks()[1].getTypeOfFile().equals("embl")) {
				
				for (int i = 0; i < ((LociHolder)viewer.getLoadedTracks()[1]).getListOfLoci().get(0).getSequence().length(); i++) {
					
					if(i%60 == 0){
						int pos = i+1;

						writer.newLine();
						writer.write(pos+" ");
						writer.flush();
					}
					if(i%10 == 0){
						writer.write(" ");
					}
					writer.write(((LociHolder)viewer.getLoadedTracks()[1]).getListOfLoci().get(0).getSequence().charAt(i));
				}
				writer.newLine();
				writer.write("//");
			}
			
			writer.flush();
			writer.close();
		}
	}

	/**
	 * Writes {@link Feature}S in genbank format
	 * 
	 * @param writer writer to write
	 * @param f {@link Feature} to export
	 * @throws IOException
	 */
	private void writeGenBankFeature(BufferedWriter writer, Feature f) throws IOException {
		writer.write("     " + f.getType());

		int space = 16 - f.getType().length();
		for (int k = 0; k < space; k++) {
			writer.write(" ");
		}

		if (f.getStrand().equals("-"))
			writer.write("complement(");
		if (f.getListOfPositions().size() > 1)
			writer.write("join(");

		for (int k = 0; k < f.getListOfPositions().size() - 1; k++) {
			writer.write(f.getListOfPositions().get(k).getStart()
					+ ".." + f.getListOfPositions().get(k).getStop()
					+ ",");
		}
		writer.write(f.getListOfPositions().get(
				f.getListOfPositions().size() - 1).getStart()
				+ ".."
				+ f.getListOfPositions().get(
						f.getListOfPositions().size() - 1).getStop());

		if (f.getStrand().equals("-"))
			writer.write(")");
		if (f.getListOfPositions().size() > 1)
			writer.write(")");
		writer.flush();

		for (int k = 0; k < f.getAdditionalInformation().size(); k++) {
			if( f.getAdditionalInformation().get(k).toString().startsWith("/")){
				writer.newLine();
				writer.write("                     " + f.getAdditionalInformation().get(k).toString());
			}
			else{
				writer.newLine();
				writer.write("                     /note=\"" + f.getAdditionalInformation().get(k).toString()+"\"");
			}
		}
		writer.flush();
	}
}
